#region License
/*
The MIT License

Copyright (c) 2008 Sky Morey

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#endregion
using System.Globalization;
using System.Collections.Generic;
using System.Abstract;
namespace System
{
    public static partial class FormatterEx
    {
        #region Registration

        private static Dictionary<Type, object> _objectFormatterProviders = null;

        public interface IObjectFormatterBuilder
        {
            IObjectFormatter<T> Build<T>();
        }

        public interface IObjectFormatter<T>
        {
            string Format(object value, Nparams param);
        }

        public static void RegisterObjectFormatter<T>(object objectFormatter) { RegisterObjectFormatter(typeof(T), objectFormatter); }
        public static void RegisterObjectFormatter(Type key, object objectFormatter)
        {
            if (_objectFormatterProviders == null)
                _objectFormatterProviders = new Dictionary<Type, object>();
            _objectFormatterProviders.Add(key, objectFormatter);
        }

        private static IObjectFormatter<T> ScanForObjectFormatter<T>(Type type)
        {
            if (_objectFormatterProviders != null)
                foreach (var objectFormatter2 in _objectFormatterProviders)
                    if ((type == objectFormatter2.Key) || (type.IsSubclassOf(objectFormatter2.Key)))
                        return ((IObjectFormatter<T>)objectFormatter2.Value);
            Type key;
            IObjectFormatter<T> objectFormatter;
            if (FormatterEx.TryScanForObjectFormatter<T>(out key, out objectFormatter))
            {
                RegisterObjectFormatter(key, objectFormatter);
                return objectFormatter;
            }
            return null;
        }

        private static bool TryScanForObjectFormatter<T>(out Type key, out IObjectFormatter<T> objectFormatter)
        {
            //var interfaces = type.FindInterfaces(((m, filterCriteria) => m == s_objectParserBuilderType), null);
            throw new NotImplementedException();
        }

        #endregion

        internal static class ObjectFormatterDelegateFactory<T, TValue>
        {
            private static readonly Type _type = typeof(T);
            public static readonly Func<object, Nparams, string> Format = CreateFormatter(_type);

            static ObjectFormatterDelegateFactory() { }

            private static Func<object, Nparams, string> CreateFormatter(Type type)
            {
                if (type == Internal.BoolType)
                    return new Func<object, Nparams, string>(Formatter_Bool);
                if (type == Internal.NBoolType)
                    return new Func<object, Nparams, string>(Formatter_NBool);
                if (type == Internal.DateTimeType)
                    return new Func<object, Nparams, string>(Formatter_DateTime);
                if (type == Internal.NDateTimeType)
                    return new Func<object, Nparams, string>(Formatter_NDateTime);
                if (type == Internal.DecimalType)
                    return new Func<object, Nparams, string>(Formatter_Decimal);
                if (type == Internal.NDecimalType)
                    return new Func<object, Nparams, string>(Formatter_NDecimal);
                if (type == Internal.Int32Type)
                    return new Func<object, Nparams, string>(Formatter_Int32);
                if (type == Internal.NInt32Type)
                    return new Func<object, Nparams, string>(Formatter_NInt32);
                if (type == Internal.StringType)
                    return new Func<object, Nparams, string>(Formatter_String);
                var formatter = ScanForObjectFormatter<T>(type);
                if (formatter != null)
                    return formatter.Format;
                return new Func<object, Nparams, string>(Formatter_Default);
            }

            #region Default

            private static string Formatter_Default(object value, Nparams param)
            {
                var valueAsT = ParserEx.Parse<T>(value);
                return (valueAsT != null ? valueAsT.ToString() : string.Empty);
            }

            #endregion

            #region Bool

            private static string Formatter_Bool(object value, Nparams param)
            {
                var valueAsBool = ParserEx.Parse<bool>(value);
                return (valueAsBool ? bool.TrueString : bool.FalseString);
            }
            private static string Formatter_NBool(object value, Nparams param)
            {
                var valueAsBool = ParserEx.Parse<bool?>(value);
                return (valueAsBool.HasValue ? (valueAsBool.Value ? bool.TrueString : bool.FalseString) : string.Empty);
            }

            #endregion

            #region DateTime

            private static string Formatter_DateTime(object value, Nparams param)
            {
                var valueAsDateTime = ParserEx.Parse<DateTime>(value);
                return valueAsDateTime.ToString("M/d/yyyy hh:mm tt", CultureInfo.InvariantCulture);
            }
            private static string Formatter_NDateTime(object value, Nparams param)
            {
                var valueAsDateTime = ParserEx.Parse<DateTime?>(value);
                return (valueAsDateTime.HasValue ? valueAsDateTime.Value.ToString("M/d/yyyy hh:mm tt", CultureInfo.InvariantCulture) : string.Empty);
            }

            #endregion

            #region Decimal

            private static string Formatter_Decimal(object value, Nparams param)
            {
                var valueAsDecimal = ParserEx.Parse<decimal>(value);
                return valueAsDecimal.ToString("0.0000", CultureInfo.InvariantCulture);
            }
            private static string Formatter_NDecimal(object value, Nparams param)
            {
                var valueAsDecimal = ParserEx.Parse<decimal?>(value);
                return (valueAsDecimal.HasValue ? valueAsDecimal.Value.ToString("0.0000", CultureInfo.InvariantCulture) : string.Empty);
            }

            #endregion

            #region Int32

            private static string Formatter_Int32(object value, Nparams param)
            {
                var valueAsInt32 = ParserEx.Parse<int>(value);
                return valueAsInt32.ToString(CultureInfo.InvariantCulture);
            }
            private static string Formatter_NInt32(object value, Nparams param)
            {
                var valueAsInt32 = ParserEx.Parse<int?>(value);
                return (valueAsInt32.HasValue ? valueAsInt32.Value.ToString(CultureInfo.InvariantCulture) : string.Empty);
            }

            #endregion

            #region String

            private static string Formatter_String(object value, Nparams param)
            {
                return ParserEx.Parse<string>(value);
            }

            #endregion
        }
    }
}
